package hu.myai.indicators;

import hu.myai.api.indicators.AbstractIndicator;
import hu.myai.model.IndicatorVO;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author bozbalint
 * 
 */
public class RSIIndicator extends AbstractIndicator {

    private Double avgGain;
    private Double avgLoss;

    /**
     * The object used when logging debug,errors,warnings and info.
     * */
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    public RSIIndicator(Double parameter) {
        super(parameter);
    }

    @Override
    public void init() {
    }

    /**
     * It is the traditional RSI calculation.
     * */

    @Override
    protected IndicatorVO indicatorCalculation() {

        if (tickHistory.size() < parameter)
            return null;

        IndicatorVO indicator = new IndicatorVO();
        indicator.setDate(lastTick.getTime());

        if (avgGain == null || avgLoss == null) {
            // first average calculation

            double actValue = tickHistory.get(0).getClose();
            double pSum = 0, nSum = 0;

            // iterate loop is defined by the parameter
            for (int i = 1; i < parameter.intValue(); i++) {
                double prevValue = tickHistory.get(i).getClose();
                if (actValue > prevValue) {
                    pSum += actValue - prevValue;
                } else {
                    nSum += prevValue - actValue;
                }
                actValue = prevValue;
            }

            avgGain = pSum / parameter.intValue();
            avgLoss = nSum / parameter.intValue();
        } else {
            // accumulation calculation
            double change = tickHistory.get(0).getClose() - tickHistory.get(1).getClose();
            avgGain = (avgGain * (parameter.intValue() - 1) + (change > 0 ? change : 0)) / parameter.intValue();
            avgLoss = (avgLoss * (parameter.intValue() - 1) + (change > 0 ? 0 : -1 * change)) / parameter.intValue();
        }

        indicator.setValue(indexCalculation(avgGain, avgLoss));
        indicator.setChanged(true);

        log.debug(indicator.toString());
        return indicator;
    }

    private double indexCalculation(double posSum, double negSum) {

        if (negSum != 0) {
            return 100 - (100 / (1 + posSum / negSum));
        } else {
            return 100;
        }
    }
}
